/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator;

import static io.iec.edp.caf.runtime.config.BeanUtil.getAppCtx;

import com.inspur.edp.bef.bizentity.GspBusinessEntity;
import com.inspur.edp.bff.designtime.generator.changeconvertor.FSChangeConvertorGenContext;
import com.inspur.edp.bff.designtime.generator.common.IMetadataPool;
import com.inspur.edp.bff.designtime.generator.common.MetadataInfo;
import com.inspur.edp.bff.designtime.generator.entity.VmEntityGenContext;
import com.inspur.edp.bff.designtime.generator.entitydataconvertor.VMObjectDataConvertorGenContext;
import com.inspur.edp.bff.designtime.generator.udt.UdtInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.item.ClassGeneratorContext;
import com.inspur.edp.caf.generator.module.ModuleGenerator;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.entity.config.MgrConfig;
import com.inspur.edp.cef.generator.entityGenerator.base.dataTypeData.DataTypeDataGenerator;
import com.inspur.edp.cef.generator.overall.commonModel.CommonModelGeneratorContext;
import com.inspur.edp.cef.variable.dtgenerator.VariableGeneratorContext;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.runtime.config.BeanUtil;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;

public class VmGeneratorContext extends CommonModelGeneratorContext implements IMetadataPool {




    private RefCommonService lcmDtService;
    private RefCommonService getLcmDtService(){
        if(lcmDtService == null){
            lcmDtService = SpringBeanUtils.getBean(RefCommonService.class);
        }
        return lcmDtService;
    }
//    private MetadataService metedataService;
//    private MetadataService getMetedataService(){
//        if(metedataService == null){
//            metedataService = getAppCtx().getBean(MetadataService.class);
//        }
//        return metedataService;
//    }
    // region BasicInfo

    private HashMap<String, UdtInfo> udtCollection;


    //public MetadataJitContext MetadataJitContext { get; internal set; }

    private GspViewModel parentVo;

    public final GspViewModel getParentVo() {
        return parentVo;
    }

    public final void setParentVo(GspViewModel value) {
        parentVo = value;
    }

    private String privateParentNamespace;

    public final String getParentNamespace() {
        return privateParentNamespace;
    }

    public final void setParentNamespace(String value) {
        privateParentNamespace = value;
    }

    private ModuleGenerator refGenerator;

    public final ModuleGenerator getRefGenerator() {
        return refGenerator;
    }

    public final void setRefGenerator(ModuleGenerator value) {
        refGenerator = value;
    }

    private GspViewModel vo;

    public final GspViewModel getVm() {
        return vo;
    }

    public final void setVm(GspViewModel value) {
        vo = value;
    }

    //public GSPMetadata Metadata { get; set; }
    private GspBusinessEntity refBizEntity;

    public final GspBusinessEntity getRefBizEntity() {
        return refBizEntity;
    }

    public final void setRefBizEntity(GspBusinessEntity value) {
        refBizEntity = value;
    }

    private LinkedHashMap<String, GspMetadata> refEntityCollection = new LinkedHashMap<String, GspMetadata>();

    public final LinkedHashMap<String, GspMetadata> getRefEntityCollection() {
        return refEntityCollection;
    }

    public final void setRefEntityCollection(LinkedHashMap<String, GspMetadata> value) {
        refEntityCollection = value;
    }

    private GspBusinessEntity refTemplateBizEntity;
    public final GspBusinessEntity getRefTemplateBizEntity() {

        return refTemplateBizEntity;
    }

    public final void setRefTemplateBizEntity(GspBusinessEntity value) {
        refTemplateBizEntity = value;
    }

//    private QueryObject privateRefQo;
//    public final QueryObject getRefQo()
//    {
//        return privateRefQo;
//    }
//    public final void setRefQo(QueryObject value)
//    {
//        privateRefQo = value;
//    }
//
//    public QueryNode RefQueryNode => getRefQo().QueryNode;

    //    public final Assembly getRefEntityAssembly()
//    {
//        if (getRefBizEntity() != null)
//        {
//            return GetMetadataInfo(null, getRefBizEntity().ID).BelongAssembly;
//        }
//        return GetMetadataInfo(null, getRefQo().ID).BelongAssembly;
//    }
    private String voNamespace;

    public final String getVmNamespace() {
        return voNamespace;
    }

    public final void setVmNamespace(String value) {
        voNamespace = value;
    }

    public IMetadataPool getMetadataPool() {
        return this;
    }

    //public string MetadataPath { get; internal set; }

    private HashMap<String, VMObjectDataConvertorGenContext> dataConvertorContext = new HashMap<String, VMObjectDataConvertorGenContext>();

    public final HashMap<String, VMObjectDataConvertorGenContext> getDataConvertorContext() {
        return dataConvertorContext;
    }


    //public bool PreGenerating { get; set; }

    private VmEntityGenContext entityContext;

    public final VmEntityGenContext getEntityContext() {
        return entityContext;
    }

    public final void setEntityContext(VmEntityGenContext value) {
        entityContext = value;
    }

    @Override
    public IGspCommonDataType getCommonDataType() {
        return getVm().getMainObject();
    }

    @Override
    public String getDataTypeNamespace() {
        return getVmNamespace();
    }

    private String coreAssemblyName;

    public final String getCoreAssemblyName() {
        return coreAssemblyName;
    }

    public final void setCoreAssemblyName(String value) {
        coreAssemblyName = value;
    }

    // endregion

    // region Type Info
    //entity
    private HashMap<String, TypeInfo> nodeTypes;

    public final HashMap<String, TypeInfo> getNodeTypes() {
        if (nodeTypes == null) {
            initNodeTypes();
        }
        return nodeTypes;
    }

    private void initNodeTypes() {
        nodeTypes = new HashMap<String, TypeInfo>();
        ArrayList<IGspCommonObject> objs = getVm().getAllObjectList();
        for (IGspCommonObject item : objs) {
            String itmeName = DataTypeDataGenerator.getName(item);
            TypeInfo typeInfo = new TypeInfo(itmeName);
            typeInfo.setTypePackageName(item.getGeneratedEntityClassInfo().getClassNamespace());
            nodeTypes.put(item.getCode(), typeInfo);
        }
    }

    //Api
    public TypeInfo getVmMgrInterfaceType() {
        String className = String.format("I%1$sManager", getVm().getCode());
        TypeInfo typeInfo = new TypeInfo(className);
        typeInfo.setTypePackageName(getVm().getApiNamespace().getDefaultNamespace());
        return typeInfo;
    }


    public TypeInfo getVmAllMgrInterfaceType(){

        String className = String.format("I%1$sService", getVm().getCode());
        TypeInfo typeInfo = new TypeInfo(className);
        typeInfo.setTypePackageName(getVm().getApiNamespace().getDefaultNamespace());
        return typeInfo;
    }


    //    private Assembly privateApiAssembly;
//    public final Assembly getApiAssembly()
//    {
//        return privateApiAssembly;
//    }
//    public final void setApiAssembly(Assembly value)
//    {
//        privateApiAssembly = value;
//    }
//    private Assembly privateEntityAssembly;
//    public final Assembly getEntityAssembly()
//    {
//        return privateEntityAssembly;
//    }
//    public final void setEntityAssembly(Assembly value)
//    {
//        privateEntityAssembly = value;
//    }
    private String voGeneratePath;

    public final String getVoGeneratePath() {
        return voGeneratePath;
    }

    public final void setVoGeneratePath(String value) {
        voGeneratePath = value;
    }

    @Override
    public String getGeneratePath() {
        return getVoGeneratePath();
    }
    //public string RelativeGeneratePath { get; internal set; }

    private String binPath;

    public final String getBinPath() {
        return binPath;
    }

    public final void setBinPath(String value) {
        binPath = value;
    }
    //public string ParentGeneratePath { get; internal set; }

    //core
    private TypeInfo voMgrImplType;

    public final TypeInfo getVmMgrImplType() {
        return voMgrImplType;
    }

    public final void setVmMgrImplType(TypeInfo value) {
        voMgrImplType = value;
    }

    private String voMgrImplAssembly;

    public final String getVmMgrImplAssembly() {
        return voMgrImplAssembly;
    }

    public final void setVmMgrImplAssembly(String value) {
        voMgrImplAssembly = value;
    }

    private String vmMgrImplClassName;

    public final String getVmMgrImplClassName() {
        return vmMgrImplClassName;
    }

    public final void setVmMgrImplClassName(String value) {
        vmMgrImplClassName = value;
    }

    private String abstractVoChangeConvertorName;

    public final String getAbstractVoChangeConvertorName() {
        return abstractVoChangeConvertorName;
    }

    public final void setAbstractVoChangeConvertorName(String value) {
        abstractVoChangeConvertorName = value;
    }

    private String defaultValueConverterName;

    public final String getDefaultValueConverterName() {
        return defaultValueConverterName;
    }

    public final void setDefaultValueConverterName(String value) {
        defaultValueConverterName = value;
    }

    private FSChangeConvertorGenContext changeConvertorGenContext;

    public final FSChangeConvertorGenContext getChangeConvertorGenContext() {
        return changeConvertorGenContext;
    }

    public final void setChangeConvertorGenContext(FSChangeConvertorGenContext value) {
        changeConvertorGenContext = value;
    }

    public final TypeInfo getChangeConvertorType() {
        String className = String.format("%1$sChangeConvertor", getVm().getMainObject().getCode());
        TypeInfo typeInfo = new TypeInfo(className);
        typeInfo.setTypePackageName(getVm().getEntityAssemblyInfo().getDefaultNamespace());
        return typeInfo;
    }

    private ClassGeneratorContext changesetGenContext;

    public final ClassGeneratorContext getChangesetGenContext() {
        return changesetGenContext;
    }

    public final void setChangesetGenContext(ClassGeneratorContext value) {
        changesetGenContext = value;
    }

    public final TypeInfo getChangesetType() {
        String className = getVm().getChangesetClassName();
        TypeInfo typeInfo = new TypeInfo(className);
        typeInfo.setTypePackageName(getVm().getEntityAssemblyInfo().getDefaultNamespace());
        return typeInfo;
    }

    private VMObjectDataConvertorGenContext mainObjectDataConvertorGenContext;

    public final VMObjectDataConvertorGenContext getMainObjectDataConvertorGenContext() {
        return mainObjectDataConvertorGenContext;
    }

    public final void setMainObjectDataConvertorGenContext(VMObjectDataConvertorGenContext value) {
        mainObjectDataConvertorGenContext = value;
    }

    public final TypeInfo getDataConvertorType() {
        String className = String.format("%1$sConvertor", getVm().getMainObject().getCode());
        TypeInfo typeInfo = new TypeInfo(className);
        typeInfo.setTypePackageName(getVm().getEntityAssemblyInfo().getDefaultNamespace());
        return typeInfo;

    }

    public final TypeInfo getFilterConvertorType() {
        String className = String.format("%1$sFilterConvertor", getVm().getMainObject().getCode());
        TypeInfo typeInfo = new TypeInfo(className);
        typeInfo.setTypePackageName(getVm().getEntityAssemblyInfo().getDefaultNamespace());
        return typeInfo;
    }

    private ClassGeneratorContext defaultValueMapContext;

    public final ClassGeneratorContext getDefaultValueMapContext() {
        return defaultValueMapContext;
    }

    public final void setDefaultValueMapContext(ClassGeneratorContext value) {
        defaultValueMapContext = value;
    }

    public final TypeInfo GetDefaultValueConvertorType() {
        String className = String.format("%1$sDefaultValueMapConvertor", getVm().getMainObject().getCode());
        TypeInfo typeInfo = new TypeInfo(className);
        typeInfo.setTypePackageName(getVm().getEntityAssemblyInfo().getDefaultNamespace());
        return typeInfo;
    }

    private ClassGeneratorContext defaultValueTypeContext;

    public final ClassGeneratorContext getDefaultValueTypeContext() {
        return defaultValueTypeContext;
    }

    public final void setDefaultValueTypeContext(ClassGeneratorContext value) {
        defaultValueTypeContext = value;
    }

    //public ProjectGeneratorContext ApiGenContext { get; set; }

    //public ProjectGeneratorContext EntityGenContext { get; set; }

    //public ProjectGeneratorContext CoreGenContext { get; set; }

    //public ProjectGeneratorContext RepoGenContext => throw new Exception("变量无须持久化。");

    private MgrConfig varConfig;

    public final MgrConfig getVarConfig() {
        return varConfig;
    }

    public final void setVarConfig(MgrConfig value) {
        varConfig = value;
    }

    public final TypeInfo getDefaultValueType() {
        String className =  getVm().getDefaultValueClassName();
        TypeInfo typeInfo = new TypeInfo(className);
        typeInfo.setTypePackageName(getVm().getEntityAssemblyInfo().getDefaultNamespace());
        return typeInfo;
    }

    private VariableGeneratorContext privateVarGenCtx;

    public final VariableGeneratorContext getVarGenCtx() {
        return privateVarGenCtx;
    }

    public final void setVarGenCtx(VariableGeneratorContext value) {
        privateVarGenCtx = value;
    }

    // endregion


    // region MetadataCache
    private final Object mdPoolLock = new Object();

    //key是元数据id, 如果要求包名改成包名+id
    private final HashMap<MetaKey, MetadataInfo> metadataPools = new HashMap<MetaKey, MetadataInfo>();

    public MetadataInfo getMetadataInfo(String packageName, String id) {
        if (DotNetToJavaStringHelper.isNullOrEmpty(packageName)) {
            packageName = null;
        }
        MetaKey key = new MetaKey(id, packageName);
        synchronized (mdPoolLock) {
            if (!metadataPools.containsKey(key))
            {
//                VmGeneratorContext vmGeneratorContext=getMainObjectDataConvertorGenContext().getVmGeneratorContext();
                GspMetadata metadata = getEntityContext().getCefGenContext().getMetadataJitContext().getMetadata(id);
                MetadataInfo metadataInfo = new MetadataInfo(metadata, getMetadataPath());
                metadataPools.put(key, metadataInfo);
            }

            return metadataPools.get(key);
        }
    }


    public<T> T getMetadataContent(String packageName, String id){
        MetadataInfo metadataInfo = getMetadataInfo(packageName, id);
        return (T) metadataInfo.getMetadata().getContent();
    }

//    public GspMetadata getMetadata(String packageName, String id) {
//        MetadataInfo metadataInfo = getMetadataInfo(packageName, id);
//        return metadataInfo.getMetadata();
//    }
//
//    private String getMetadataNamespace(String path) {
//        return metedataService.getMetadataWithoutContent(path).Header.NameSpace;
//    }

    public String getMetadataNamespace(String packageName, String id) {
        MetadataInfo metadataInfo = GetMetadataInfo(packageName, id);
        return metadataInfo.getMetadata().getHeader().getNameSpace();

    }

    private MetadataInfo GetMetadataInfo(String packageName, String id) {
        return GetMetadataInfo(packageName, id);
    }


    private final class MetaKey {
        public MetaKey(String id, String packageName) {
            this.id = id;
            this.packageName = packageName;
        }

        private String id;

        public String getId() {
            return id;
        }

        private String packageName;

        public String getPackageName() {
            return packageName;
        }
    }
    //endregion

    //region 方法

    public final UdtInfo getUdtInfo(String udtId, String udtPkgName) {
        if (udtCollection != null && udtCollection.containsKey(udtId)) {
            return udtCollection.get(udtId);
        }
        if (udtCollection == null) {
            udtCollection = new HashMap<String, UdtInfo>();
        }

        MetadataInfo metadataInfo = getMetadataPool().getMetadataInfo(null, udtId);

        UnifiedDataTypeDef udt = (UnifiedDataTypeDef)((metadataInfo.getMetadata().getContent() instanceof UnifiedDataTypeDef)
                ? metadataInfo.getMetadata().getContent() : null);
        if (udt == null) {
            throw new RuntimeException("ID为【" + udtId + "】的业务字段元数据没有获取成功");
        }


        String entityTypeName = udt.getGeneratedEntityClassInfo().getClassFullName();
        TypeInfo udtType = new TypeInfo(udt.getGeneratedEntityClassInfo().getClassName());
        udtType.setTypePackageName(udt.getGeneratedEntityClassInfo().getClassNamespace());

        UdtInfo tempVar = new UdtInfo();
        tempVar.setUdtMetadata(udt);
        tempVar.setUdtType(udtType);

//        tempVar.UdtManagerType = null;
        UdtInfo info = tempVar;
        udtCollection.put(udtId, info);
        return info;
    }

    // endregion

    public Boolean getEnableStdDateTime() {
        return vo.getEnableStdTimeFormat();
    }

    private VariableGeneratorContext varGenerateContext;

    public VariableGeneratorContext getVarGenerateContext() {
        return varGenerateContext;
    }

    public void setVarGenerateContext(VariableGeneratorContext varGenerateContext) {
        this.varGenerateContext = varGenerateContext;
    }

}
